package com.jayanslow.lighting.protocol.commands;
import com.jayanslow.lighting.protocol.misc.Bytes;



public class Dmx {
	public static final short CHAN_MIN = 1;
	public static final short CHAN_MAX = 512;
	public static final short VAL_MIN = 0;
	public static final short VAL_MAX = 255;
	public static final int TIME_MIN = 0;
	public static final int TIME_MAX = 16777215;
	
	public enum DmxCommand {
		GET (0x01), GET_RANGE (0x02), GET_ALL (0x03), SET (0x04), SET_FADE (0x05), SET_RANGE (0x06), SET_RANGE_FADE (0x07);
		private DmxCommand(int s) { this.code = (short) s; }
		private final short code;
		public short getCode() { return code; }
		public static DmxCommand valueOf(short s) { 
			for (DmxCommand c : DmxCommand.values()) { if (c.getCode() == s) return c; }
			return null;
		}
	}
	
	public static short toChannel(short s1, short s2) {
		short s = Bytes.to16bit(s1, s2);
		if (s > Dmx.CHAN_MAX) s = Dmx.CHAN_MAX;
		if (s < Dmx.CHAN_MIN) s = Dmx.CHAN_MIN;
		return s;
	}
	public static short toValue(short s) {
		if (s > Dmx.VAL_MAX) s = Dmx.VAL_MAX;
		if (s < Dmx.VAL_MIN) s = Dmx.VAL_MIN;
		return s;
	}
	public static int toTime(short s1, short s2, short s3) {
		int s = Bytes.to24bit(s1, s2, s3);
		if (s > Dmx.TIME_MAX) s = Dmx.TIME_MAX;
		if (s < Dmx.TIME_MIN) s = Dmx.TIME_MIN;
		return s;
	}
	
	public static short[] getDmx(short c) throws ChannelOutOfBoundsException {
		if (c < CHAN_MIN || c > CHAN_MAX) throw new ChannelOutOfBoundsException();
		
		short code = DmxCommand.GET.getCode();
		short[] chanBytes = Bytes.toBytes(c);
		
		return new short[] { code, chanBytes[0], chanBytes[1] };
	}
	public static short[] getDmxRange(short s, short e) throws ChannelOutOfBoundsException {
		if (s < CHAN_MIN || s > CHAN_MAX) throw new ChannelOutOfBoundsException();
		if (e < CHAN_MIN || e > CHAN_MAX) throw new ChannelOutOfBoundsException();
		
		short code = DmxCommand.GET_RANGE.getCode();
		short[] startBytes = Bytes.toBytes(s);
		short[] endBytes = Bytes.toBytes(e);
		
		return new short[] { code, startBytes[0], startBytes[1], endBytes[0], endBytes[1] };
	}
	public static short[] getAllDmx() {
		short code = DmxCommand.GET_ALL.getCode();
		return new short[] { code };
	}
	public static short[] setDmx(short c, short v) throws ChannelOutOfBoundsException, ValueOutOfBoundsException {
		if (c < CHAN_MIN || c > CHAN_MAX) throw new ChannelOutOfBoundsException();
		
		if (v < VAL_MIN || v > VAL_MAX) throw new ValueOutOfBoundsException();
		
		short code = DmxCommand.SET.getCode();
		short[] chanBytes = Bytes.toBytes(c);
		
		return new short[] { code, chanBytes[0], chanBytes[1], v };
	}
	public static short[] setDmxFade(short c, short v, int t) throws ChannelOutOfBoundsException, ValueOutOfBoundsException, TimeOutOfBoundsException {
		if (c < CHAN_MIN || c > CHAN_MAX) throw new ChannelOutOfBoundsException();
		
		if (v < VAL_MIN || v > VAL_MAX) throw new ValueOutOfBoundsException();
		
		if (t < TIME_MIN || t > TIME_MAX) throw new TimeOutOfBoundsException();
		if (t == 0) setDmx(c,v);
		
		short code = DmxCommand.SET_FADE.getCode();
		short[] chanBytes = Bytes.toBytes(c);
		short[] timeBytes = Bytes.toBytes(t);
		
		return new short[] { code, chanBytes[0], chanBytes[1], v, timeBytes[1], timeBytes[2], timeBytes[3] };
	}
	public static short[] setDmxRange(short s, short e, short v) throws ChannelOutOfBoundsException, ValueOutOfBoundsException {
		if (s < CHAN_MIN || s > CHAN_MAX) throw new ChannelOutOfBoundsException();
		if (e < CHAN_MIN || e > CHAN_MAX) throw new ChannelOutOfBoundsException();
		
		if (v < VAL_MIN || v > VAL_MAX) throw new ValueOutOfBoundsException();
		
		short code = DmxCommand.SET_RANGE.getCode();;
		short[] startBytes = Bytes.toBytes(s);
		short[] endBytes = Bytes.toBytes(e);
		
		return new short[] { code, startBytes[0], startBytes[1], endBytes[0], endBytes[1], v };
	}
	public static short[] setDmxRangeFade(short s, short e, short v, int t) throws ChannelOutOfBoundsException, ValueOutOfBoundsException, TimeOutOfBoundsException {
		if (s < CHAN_MIN || s > CHAN_MAX) throw new ChannelOutOfBoundsException();
		if (e < CHAN_MIN || e > CHAN_MAX) throw new ChannelOutOfBoundsException();
		
		if (v < VAL_MIN || v > VAL_MAX) throw new ValueOutOfBoundsException();
		
		if (t < TIME_MIN || t > TIME_MAX) throw new TimeOutOfBoundsException();
		if (t == 0) setDmxRange(s,e,v);
		
		short code = DmxCommand.SET_RANGE_FADE.getCode();;
		short[] startBytes = Bytes.toBytes(s);
		short[] endBytes = Bytes.toBytes(e);
		short[] timeBytes = Bytes.toBytes(t);
		
		return new short[] { code, startBytes[0], startBytes[1], endBytes[0], endBytes[1], v, timeBytes[1], timeBytes[2], timeBytes[3] };
	}
}
